package pers.hl.library.utils;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 二维码生成工具类
 */
public final class QRCodeUtil {

    /**
     * 生成不带logo的二维码
     */
    public static File QREncode(String content, String outputPath) throws WriterException, IOException {
        return QREncode(content, outputPath, null);
    }

    /**
     * 生成二维码
     *
     * @param content    二维码内容 mock "src/main/resources/static/image/qr/头像.jpeg"
     * @param outputPath 输出位置   mock "src/main/resources/static/image/qr/qr2.png"
     * @param logoPath   logo文件位置
     * @return
     */
    public static File QREncode(String content, String outputPath, String logoPath) throws WriterException, IOException {
        int width = 200; // 宽度
        int height = 200; // 高度
        String format = "png"; // 图片类型
        Map<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 设置内容编码格式
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // 设置纠错等级
        hints.put(EncodeHintType.MARGIN, 1); //设置二维码边的空度，非负数
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
        //MatrixToImageWriter.writeToPath(bitMatrix, format, new File("src/main/resources/static/image/qr/qr1.png").toPath());

        /*
        存在问题：能够正常生成二维码，但是生成二维码logo会变成黑白色
        原因：MatrixToImageConfig默认黑白，需要设置BLACK、WHITE
        解决：https://ququjioulai.iteye.com/blog/2254382
         */
        MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(0xFF000001, 0xFFFFFFFF);
        //
        BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix, matrixToImageConfig);
        if (!StringUtils.isEmpty(logoPath)) {
            // 生成带logo的二维码
            bufferedImage = LogoMatrix(MatrixToImageWriter.toBufferedImage(bitMatrix, matrixToImageConfig), new File(logoPath));
        }
        File dir = new File(outputPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        String suffix = ".png";
        File destQrcodeFile = new File(outputPath, MyUtils.getPureUUID() + System.currentTimeMillis() + suffix);
        ImageIO.write(bufferedImage, "png", destQrcodeFile);
        LogUtils.i("二维码文件输出成功，位置：" + destQrcodeFile.getAbsolutePath());
        return destQrcodeFile;
    }

    /**
     * 二维码添加logo
     *
     * @param matrixImage 源二维码图片
     * @param logoFile    logo图片
     * @return 返回带有logo的二维码图片
     * @throws IOException
     */
    public static BufferedImage LogoMatrix(BufferedImage matrixImage, File logoFile) throws IOException {
        Graphics2D graphics2D = matrixImage.createGraphics();
        int martixWidth = matrixImage.getWidth();
        int martixHeight = matrixImage.getHeight();

        // 读取Logo图片
        BufferedImage logo = ImageIO.read(logoFile);
        // 开始绘制图片
        graphics2D.drawImage(logo, martixWidth / 5 * 2, martixHeight / 5 * 2, martixWidth / 5, martixHeight / 5, null); // 绘制
        BasicStroke stroke = new BasicStroke(5, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        graphics2D.setStroke(stroke); // 设置笔画对象
        // 指定弧度的圆角矩形
        RoundRectangle2D.Float round = new RoundRectangle2D.Float(martixWidth / 5 * 2, martixHeight / 5 * 2, martixWidth / 5, martixHeight / 5, 20, 20);
        graphics2D.setColor(Color.WHITE);
        graphics2D.draw(round); // 绘制圆弧矩形

        // 设置logo有一道灰色边框
        BasicStroke stroke2 = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        graphics2D.setStroke(stroke2); // 设置笔画对象
        RoundRectangle2D.Float round2 = new RoundRectangle2D.Float(martixWidth / 5 * 2 + 2, martixHeight / 5 * 2 + 2, martixWidth / 5 - 4, martixHeight / 5 - 4, 20, 20);
        graphics2D.setColor(new Color(128, 128, 128));
        graphics2D.draw(round2);

        graphics2D.dispose();
        matrixImage.flush();
        return matrixImage;
    }
}
